/**
 * 
 */
package com.cti.ftpservice.utils;

import java.io.InputStream;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * ISBN转换工具
 * 
 * @author 鲁永刚
 * 
 */
public class IsbnConvertUtils {
	private static Element rootElement = null;

	static {
		SAXReader reader = new SAXReader();
		InputStream in = IsbnConvertUtils.class.getClassLoader().getResourceAsStream("isbnRang.xml");
		try {
			Document document = reader.read(in);
			rootElement = document.getRootElement();
		} catch (DocumentException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 将输入的ISBN号转换为四中格式 分别为 13位，13位加横线，10位，10位加横线
	 * 
	 * @param inputIsbn
	 * @return
	 * @throws Exception
	 */
	public static String[] convert(String inputIsbn) throws Exception {
		String[] isbns = new String[4];
		isbns[0] = convertTo13place(inputIsbn);
		isbns[1] = convertTo13placeAndSeparationLine(inputIsbn);
		isbns[2] = convertTo10place(inputIsbn);
		isbns[3] = convertTo10placeAndSeparationLine(inputIsbn);
		return isbns;
	}

	/**
	 * 将输入的isbn号转换为10位且加分隔线的isbn号
	 * 
	 * @param inputIsbn
	 * @return
	 * @throws Exception
	 */
	public static String convertTo10placeAndSeparationLine(String inputIsbn) throws Exception {
		String isbn = convertTo13placeAndSeparationLine(inputIsbn);
		return isbn.substring(4, isbn.length() - 1) + generate10placeCheckCode(isbn.replace("-", "").substring(3, 13));
	}

	/**
	 * 将输入的isbn号转换为10位isbn号
	 * 
	 * @param inputIsbn
	 * @return
	 * @throws Exception
	 */
	public static String convertTo10place(String inputIsbn) throws Exception {
		if (!validate(inputIsbn))
			throw new Exception("ISBN号有误:" + inputIsbn);
		String isbn = trimIsbn(inputIsbn);
		if (isbn.length() == 13||isbn.length()==12) {
			return convert13placeTo10place(isbn);
		}
		return generate10placeCorrectIsbn(isbn);
	}

	/**
	 * @param isbn
	 * @return
	 */
	private static String convert13placeTo10place(String inputIsbn) {
		String isbn = inputIsbn.substring(3);
		return generate10placeCorrectIsbn(isbn);
	}

	/**
	 * 将输入的isbn转换为13位并且加分隔线的isbn号
	 * 
	 * @param inputIsbn
	 * @return
	 * @throws Exception
	 */
	public static String convertTo13placeAndSeparationLine(String inputIsbn) {
		// 将输入的isbn号转换为13位isbn号
		String isbn = convertTo13place(inputIsbn);
		// ISBN号的组成：前缀-组号-出版社号-数序号-校验码
		int currentIndex = 0;
		StringBuffer sb = new StringBuffer();
		sb.append(isbn.substring(0, 3));
		sb.append("-");
		currentIndex += 3;
		// 组号为1到5位，XML存放的格式为：前缀-组号，如978-7，因此提输入的ISBN号的前三位+“-”+后五位
		String groupNum = isbn.substring(0, 3) + "-" + isbn.substring(3, 8);
		// 在XML文件中分别以1位，2位，3位，4位，5位来匹配组号，如果没有匹配的，则认为ISBN13不合法
		Element groupElement = getGroupElementByGroupNum(groupNum);
		String groupValue = groupElement.elementTextTrim("Prefix");
		int groupLen = groupValue.split("-")[1].length();
		sb.append(isbn.subSequence(currentIndex, currentIndex + groupLen));
		currentIndex += groupLen;
		sb.append("-");
		// 提取出版社号，在XML文件中，出版社号的范围都是7位，因此这里截取组号的后7位
		int publishNumLength = currentIndex + 7 > isbn.length() ? isbn.length() - currentIndex : 7;
		String publishNum = isbn.substring(currentIndex, currentIndex + publishNumLength);
		int publishLength = getPublishLengthByPublishNum(groupElement, publishNum);
		sb.append(isbn.substring(currentIndex, currentIndex + publishLength));
		currentIndex += publishLength;
		sb.append("-");
		sb.append(isbn.substring(currentIndex, 12));
		sb.append("-");
		sb.append(isbn.charAt(12));
		return sb.toString();
	}

	/**
	 * @param groupElement
	 * @param publishNum
	 * @return
	 * @throws Exception
	 */
	private static int getPublishLengthByPublishNum(Element groupElement, String publishNum) {
		int value = Integer.parseInt(publishNum);
		for (Object obj : groupElement.element("Rules").elements("Rule")) {
			Element element = (Element) obj;
			String rangValue = element.elementTextTrim("Range");
			String[] rangSplits = rangValue.split("-");
			int rang1 = Integer.parseInt(rangSplits[0]);
			int rang2 = Integer.parseInt(rangSplits[1]);
			if (value >= rang1 && value <= rang2) {
				return Integer.parseInt(element.elementTextTrim("Length"));
			}
		}
		throw new RuntimeException("未能找到出版社对应的的长度：" + publishNum);
	}

	/**
	 * @param groupNum
	 * @return
	 */
	private static Element getGroupElementByGroupNum(String groupNum) {
		Element resuleElement = null;
		Element registrationGroupElement = rootElement.element("RegistrationGroups");
		registrationGroupElement.elements("Group");
		for (Object obj : registrationGroupElement.elements("Group")) {
			Element element = (Element) obj;
			if (element.elementTextTrim("Prefix").equals(groupNum)) {
				resuleElement = element;
				break;
			}
		}
		if (resuleElement == null) {
			Element EANUCCPrefixesElement = rootElement.element("EAN.UCCPrefixes");
			for (Object obj : EANUCCPrefixesElement.elements("EAN.UCC")) {
				Element element = (Element) obj;
				if (element.elementTextTrim("Prefix").equals(groupNum)) {
					resuleElement = element;
					break;
				}
			}
		}
		if (resuleElement == null) {
			if (groupNum.length() > 4) {
				return getGroupElementByGroupNum(groupNum.substring(0, groupNum.length() - 1));
			}
		}
		return resuleElement;
	}

	/**
	 * 将输入的isbn号转换为13位isbn号
	 * 
	 * @param inputIsbn
	 * @return
	 * @throws Exception
	 */
	public static String convertTo13place(String inputIsbn)  {
		if (!validate(inputIsbn))
			throw new RuntimeException("ISBN号有误:" + inputIsbn);
		String isbn = trimIsbn(inputIsbn);
		if (isbn.length() == 10||isbn.length()==9) {
			return convert10placeTo13place(isbn);
		}
		return generate13placeCorrectIsbn(isbn);
	}

	/**
	 * 将10位isbn转换为13位isbn
	 * 
	 * @param inputIsbn
	 * @return
	 */
	private static String convert10placeTo13place(String inputIsbn) {
		if(inputIsbn.length()==0)
			inputIsbn=generate10placeCheckCode(inputIsbn);
		String isbn="978" + inputIsbn;
		return generate13placeCorrectIsbn(isbn);
	}

	/**
	 * 验证isbn号
	 * 
	 * @param inputIsbn
	 * @return
	 */
	public static boolean validate(String inputIsbn) {
		try {
			String isbnStr = trimIsbn(inputIsbn);
			if(isbnStr.startsWith("978")||isbnStr.startsWith("979")){
				//这是13位的
				if(isbnStr.length()!=13&&isbnStr.length()!=12){
					return false;
				}
				return check13placeIsbn(isbnStr);
			}else{
				if (isbnStr.length() != 10 && isbnStr.length() != 9)
					return false;
				return check10placeIsbn(isbnStr);
			}
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * 校验13位isbn号的最后一位
	 * 
	 * @param inputIsbn
	 * @return
	 */
	private static boolean check13placeIsbn(String inputIsbn) {
		generate13placeCorrectIsbn(inputIsbn);
		return true;
	}

	/**
	 * 校验十位isbn的最后一位
	 * 
	 * @param inputIsbn
	 * @return
	 */
	private static boolean check10placeIsbn(String inputIsbn) {
		 generate10placeCorrectIsbn(inputIsbn);
		 return true;
	}

	/**
	 * @param inputIsbn
	 * @return
	 */
	private static String generate10placeCorrectIsbn(String inputIsbn) {
		return inputIsbn.substring(0, 9) + generate10placeCheckCode(inputIsbn);
	}

	/**
	 * @param substring
	 * @return
	 */
	private static String generate10placeCheckCode(String inputIsbn) {
		int totalCount = 0;
		int tempIndex = 10;
		for (int i = 0; i < 9; i++) {
			int temp = tempIndex * Integer.parseInt(String.valueOf(inputIsbn.charAt(i)));
			tempIndex -= 1;
			totalCount += temp;
		}
		String jym = (11 - totalCount % 11) == 10 ? "X" : String.valueOf(11 - totalCount % 11);
		if (!jym.equals("X")) {
			if (Integer.parseInt(jym) == 11) {
				jym = "0";
			}
		}
		return jym;
	}

	/**
	 * @param inputIsbn
	 * @return
	 */
	private static String generate13placeCorrectIsbn(String inputIsbn) {
		return inputIsbn.substring(0, 12) + generate13placeCheckCode(inputIsbn);
	}

	/**
	 * @param inputIsbn
	 * @return
	 */
	private static String generate13placeCheckCode(String inputIsbn) {
		// 得到奇数和（即用1乘所有奇数位，数组以0记位，即偶数下标)
		int jsTotal = 0;
		for (int i = 0; i < 12; i += 2) {
			jsTotal += Integer.parseInt(String.valueOf(inputIsbn.charAt(i)));
		}
		// 得到偶然和(即用3乘所有的偶数位，数组以0记位，即奇数下标)
		int osTotal = 0;
		for (int i = 1; i < 12; i += 2) {
			osTotal += Integer.parseInt(String.valueOf(inputIsbn.charAt(i))) * 3;
		}
		int ys = (10 - (jsTotal + osTotal) % 10) == 10 ? 0 : (10 - (jsTotal + osTotal) % 10);
		return String.valueOf(ys);
	}

	/**
	 * 去掉isbn号的分隔线和前后空格
	 * 
	 * @param inputIsbn
	 * @return
	 */
	private static String trimIsbn(String inputIsbn) {
		return inputIsbn.replace("-", "").trim();
	}
}
